#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <time.h>

static void * mybrk(void * what)
{
	long rval;
	unsigned long retval;

	rval = syscall(SYS_brk, what);
	if (rval <= 0 && rval >= -4096) {
		fprintf(stderr, "Error, brk(%p) has returned: 0x%lx, %ld\n",
			what, rval, rval);
		fflush(stderr);
		_exit(1);
	}

	retval = (unsigned long) rval;
	return (void *) retval;
}

static void msleep(unsigned int msec)
{
	struct timespec spec;

	spec.tv_sec = (time_t) (msec / 1000);
	spec.tv_nsec = (long) (msec % 1000);
	spec.tv_nsec *= 1000000;
	nanosleep(&spec, NULL);
}

int main(int argc, char *argv[])
{
	int setval = 0;
	int msize = 0x400000;
	char * mptr, * nptr;

	if (argc > 1) {
		int error;
		char * endp = NULL;

		errno = 0;
		msize = (int) strtol(argv[1], &endp, 0);
		error = errno;
		if (msize < 0 || error != 0 || argv[1] == endp) {
			fprintf(stderr, "Error, invalid memory size: %s\n", argv[1]);
			fflush(stderr);
			return 1;
		}
	}

	if (argc > 2) {
		setval = (int) strtol(argv[2], NULL, 0);
		setval &= 0xff;
	}

	do { /* allocate some memory then free, to avoid glibc allocation when we do brk */
		char * p = (char *) malloc(32768);
		if (p != NULL) {
			memset(p, 0x24, 32768);
			free(p);
		}
	} while (0);

	fprintf(stdout, "Allocating memory with brk of size: %#x, data: %#x, PID: %ld\n",
		msize, setval, (long) getpid());
	fflush(stdout);
	msleep(500);

	mptr = mybrk(NULL);
	nptr = mybrk(mptr + msize);

	fprintf(stdout, "brk(%#x) has returned: %p\n", msize, mptr);
	fflush(stdout);
	memset(mptr, setval, msize);

	fputs("About to free memory...\n", stdout);
	fflush(stdout);

	mptr = mybrk(mptr);
	fprintf(stdout, "After deallocation: brk: %p, %p, delta: %#x\n",
		nptr, mptr, (unsigned int) (nptr - mptr));
	fflush(stdout);

	return 0;
}
